use std::{rc::Rc, cell::RefCell};

use crate::{instructions::base::Instruction, rtda::Frame};

// 按索引给数组元素赋值。
#[derive(Debug, Default)]
pub struct AASTORE {}

impl Instruction for AASTORE {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
         // 操作数栈
        let stack = frame.borrow().get_operand_stack();
        // 要赋给数组元素的值
        let _ref = stack.borrow_mut().pop_ref();
        // 数组索引
        let index = stack.borrow_mut().pop_int();
        // 数组引用
        let arr_ref = stack.borrow_mut().pop_ref().expect("java.lang.NullPointerException");

        let refs = unsafe { &mut *arr_ref }.array().refs();

        check_index(index, refs.len() as i32);
        refs[index as usize] = _ref;
    }
}

#[derive(Debug, Default)]
pub struct BASTORE {}

impl Instruction for BASTORE {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let val = stack.borrow_mut().pop_int();
        let index = stack.borrow_mut().pop_int();
        let arr_ref = stack.borrow_mut().pop_ref().expect("java.lang.NullPointerException");
        // let mut ref_mut = arr_ref.borrow_mut();
        let bytes = unsafe { &mut *arr_ref }.array().bytes();

        check_index(index, bytes.len() as i32);
        bytes[index as usize] = val as i8;
    }
}

#[derive(Debug, Default)]
pub struct CASTORE {}

impl Instruction for CASTORE {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let val = stack.borrow_mut().pop_int();
        let index = stack.borrow_mut().pop_int();
        let arr_ref = stack.borrow_mut().pop_ref().expect("java.lang.NullPointerException");
        // let mut ref_mut = arr_ref.borrow_mut();
        let chars = unsafe { &mut *arr_ref }.array().chars();

        check_index(index, chars.len() as i32);
        chars[index as usize] = val as u16;
    }
}

#[derive(Debug, Default)]
pub struct DASTORE {}

impl Instruction for DASTORE {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let val = stack.borrow_mut().pop_double();
        let index = stack.borrow_mut().pop_int();
        let arr_ref = stack.borrow_mut().pop_ref().expect("java.lang.NullPointerException");
        // let mut ref_mut = arr_ref.borrow_mut();
        let doubles = unsafe { &mut *arr_ref }.array().doubles();

        check_index(index, doubles.len() as i32);
        doubles[index as usize] = val;
    }
}

#[derive(Debug, Default)]
pub struct FASTORE {}

impl Instruction for FASTORE {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let val = stack.borrow_mut().pop_float();
        let index = stack.borrow_mut().pop_int();
        let arr_ref = stack.borrow_mut().pop_ref().expect("java.lang.NullPointerException");
        // let mut ref_mut = arr_ref.borrow_mut();
        let floats = unsafe { &mut *arr_ref }.array().floats();

        check_index(index, floats.len() as i32);
        floats[index as usize] = val;
    }
}

#[derive(Debug, Default)]
pub struct IASTORE {}

impl Instruction for IASTORE {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let val = stack.borrow_mut().pop_int();
        let index = stack.borrow_mut().pop_int();
        let arr_ref = stack.borrow_mut().pop_ref().expect("java.lang.NullPointerException");
        // let mut ref_mut = arr_ref.borrow_mut();
        let ints = unsafe { &mut *arr_ref }.array().ints();

        check_index(index, ints.len() as i32);
        ints[index as usize] = val;
    }
}

#[derive(Debug, Default)]
pub struct LASTORE {}

impl Instruction for LASTORE {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let val = stack.borrow_mut().pop_long();
        let index = stack.borrow_mut().pop_int();
        let arr_ref = stack.borrow_mut().pop_ref().expect("java.lang.NullPointerException");
        // let mut ref_mut = arr_ref.borrow_mut();
        let longs = unsafe { &mut *arr_ref }.array().longs();

        check_index(index, longs.len() as i32);
        longs[index as usize] = val as i64;
    }
}

#[derive(Debug, Default)]
pub struct SASTORE {}

impl Instruction for SASTORE {
    fn execute(&mut self, frame: Rc<RefCell<Frame>>) {
        let stack = frame.borrow().get_operand_stack();
        let val = stack.borrow_mut().pop_int();
        let index = stack.borrow_mut().pop_int();
        let arr_ref = stack.borrow_mut().pop_ref().expect("java.lang.NullPointerException");
        // let mut ref_mut = arr_ref.borrow_mut();
        let shorts = unsafe { &mut *arr_ref }.array().shorts();

        check_index(index, shorts.len() as i32);
        shorts[index as usize] = val as i16;
    }
}



// 用expect直接抛出异常，不清楚后续处理异常是否用到此处，暂不删除。
// fn check_not_none(arr_ref: &Option<Rc<RefCell<Object>>>) {
//     if arr_ref.is_none() {
//         panic!("java.lang.NullPointerException");
//     }
// }

fn check_index(index: i32, len: i32) {
    // IndexOutOffBounds
    if index < 0 || index >= len {
        panic!("ArrayIndexOutOffBoundsException")
    }
}

